/*
 * Copyright (C) 2017
 *
 * Brick Yang <printfxxx@163.com>
 *
 * This program is free software. You can redistribute it and/or
 * modify it as you like.
 */

/**
 * @file	dpni.c
 * @brief	dpni driver
 */

#include <mtrace.h>

#include "dpni.h"

/* Command versioning */
#define DPNI_CMD_BASE_VERSION	1
#define DPNI_CMD_2ND_VERSION	2
#define DPNI_CMD_ID_OFFSET	4

#define DPNI_CMD(id)	(((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_BASE_VERSION)
#define DPNI_CMD_V2(id)	(((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_2ND_VERSION)

/* Command IDs */
#define DPNI_CMDID_OPEN				DPNI_CMD(0x801)
#define DPNI_CMDID_CLOSE			DPNI_CMD(0x800)
#define DPNI_CMDID_ENABLE			DPNI_CMD(0x002)
#define DPNI_CMDID_DISABLE			DPNI_CMD(0x003)
#define DPNI_CMDID_GET_ATTR			DPNI_CMD(0x004)
#define DPNI_CMDID_RESET			DPNI_CMD(0x005)
#define DPNI_CMDID_IS_ENABLED			DPNI_CMD(0x006)
#define DPNI_CMDID_SET_POOLS			DPNI_CMD(0x200)
#define DPNI_CMDID_SET_ERRORS_BEHAVIOR		DPNI_CMD(0x20B)
#define DPNI_CMDID_GET_LINK_STATE		DPNI_CMD(0x215)
#define DPNI_CMDID_GET_LINK_STATE_V2		DPNI_CMD_V2(0x215)
#define DPNI_CMDID_SET_MAX_FRAME_LENGTH		DPNI_CMD(0x216)
#define DPNI_CMDID_SET_LINK_CFG			DPNI_CMD(0x21A)
#define DPNI_CMDID_SET_LINK_CFG_V2		DPNI_CMD_V2(0x21A)
#define DPNI_CMDID_SET_MCAST_PROMISC		DPNI_CMD(0x220)
#define DPNI_CMDID_SET_UNICAST_PROMISC		DPNI_CMD(0x222)
#define DPNI_CMDID_GET_STATISTICS		DPNI_CMD(0x25D)
#define DPNI_CMDID_RESET_STATISTICS		DPNI_CMD(0x25E)
#define DPNI_CMDID_GET_QUEUE			DPNI_CMD(0x25F)
#define DPNI_CMDID_SET_QUEUE			DPNI_CMD(0x260)
#define DPNI_CMDID_SET_BUFFER_LAYOUT		DPNI_CMD(0x265)
#define DPNI_CMDID_SET_TX_CONFIRMATION_MODE	DPNI_CMD(0x266)
#define DPNI_CMDID_GET_LINK_CFG			DPNI_CMD(0x278)
#define DPNI_CMDID_SET_PORT_CFG			DPNI_CMD(0x27B)
#define DPNI_CMDID_GET_PORT_CFG			DPNI_CMD(0x27C)

/* Macros for accessing command fields smaller than 1byte */
#define DPNI_MASK(field)	\
	GENMASK(DPNI_##field##_SHIFT + DPNI_##field##_SIZE - 1, \
		DPNI_##field##_SHIFT)

#define dpni_set_field(var, field, val)	\
	((var) |= (((val) << DPNI_##field##_SHIFT) & DPNI_MASK(field)))
#define dpni_get_field(var, field)	\
	(((var) & DPNI_MASK(field)) >> DPNI_##field##_SHIFT)

struct dpni_cmd_open {
	__le32 dpni_id;
};

#define DPNI_BACKUP_POOL(val, order)	(((val) & 0x1) << (order))
struct dpni_cmd_set_pools {
	/* cmd word 0 */
	u8 num_dpbp;
	u8 backup_pool_mask;
	__le16 pad;
	/* cmd word 0..4 */
	__le32 dpbp_id[DPNI_MAX_DPBP];
	/* cmd word 4..6 */
	__le16 buffer_size[DPNI_MAX_DPBP];
};

#define DPNI_ENABLE_SHIFT	0
#define DPNI_ENABLE_SIZE	1

struct dpni_rsp_is_enabled {
	u8 enabled;
};

struct dpni_rsp_get_attr {
	/* response word 0 */
	__le32 options;
	u8 num_queues;
	u8 num_tcs;
	u8 mac_filter_entries;
	u8 pad0;
	/* response word 1 */
	u8 vlan_filter_entries;
	u8 pad1;
	u8 qos_entries;
	u8 pad2;
	__le16 fs_entries;
	__le16 pad3;
	/* response word 2 */
	u8 qos_key_size;
	u8 fs_key_size;
	__le16 wriop_version;
};

#define DPNI_ERROR_ACTION_SHIFT		0
#define DPNI_ERROR_ACTION_SIZE		4
#define DPNI_FRAME_ANN_SHIFT		4
#define DPNI_FRAME_ANN_SIZE		1

struct dpni_cmd_set_errors_behavior {
	__le32 errors;
	/* from least significant bit: error_action:4, set_frame_annotation:1 */
	u8 flags;
};

#define DPNI_PASS_TS_SHIFT	0
#define DPNI_PASS_TS_SIZE	1
#define DPNI_PASS_PR_SHIFT	1
#define DPNI_PASS_PR_SIZE	1
#define DPNI_PASS_FS_SHIFT	2
#define DPNI_PASS_FS_SIZE	1

struct dpni_cmd_set_buffer_layout {
	/* cmd word 0 */
	u8 qtype;
	u8 pad0[3];
	__le16 options;
	/* from LSB: pass_timestamp:1, parser_result:1, frame_status:1 */
	u8 flags;
	u8 pad1;
	/* cmd word 1 */
	__le16 private_data_size;
	__le16 data_align;
	__le16 head_room;
	__le16 tail_room;
};

struct dpni_cmd_get_qdid {
	u8 qtype;
};

struct dpni_rsp_get_qdid {
	__le16 qdid;
};

struct dpni_cmd_get_statistics {
	u8 page_number;
};

struct dpni_rsp_get_statistics {
	__le64 counter[DPNI_STATISTICS_CNT];
};

struct dpni_cmd_link_cfg {
	/* cmd word 0 */
	__le64 pad0;
	/* cmd word 1 */
	__le32 rate;
	__le32 pad1;
	/* cmd word 2 */
	__le64 options;
	/* cmd word 3 */
	__le64 advertising;
};

struct dpni_cmd_set_link_cfg {
	/* cmd word 0 */
	__le64 pad0;
	/* cmd word 1 */
	__le32 rate;
	__le32 pad1;
	/* cmd word 2 */
	__le64 options;
	/* cmd word 3 */
	__le64 advertising;
};

#define DPNI_LINK_STATE_SHIFT	0
#define DPNI_LINK_STATE_SIZE	1
#define DPNI_STATE_VALID_SHIFT	1
#define DPNI_STATE_VALID_SIZE	1

struct dpni_rsp_get_link_state {
	/* response word 0 */
	__le32 pad0;
	/* from LSB: up:1, valid:1 */
	u8 flags;
	u8 pad1[3];
	/* response word 1 */
	__le32 rate;
	__le32 pad2;
	/* response word 2 */
	__le64 options;
	/* cmd word 3 */
	__le64 supported;
	/* cmd word 4 */
	__le64 advertising;
};

struct dpni_cmd_set_max_frame_length {
	__le16 max_frame_length;
};

struct dpni_cmd_set_multicast_promisc {
	u8 enable;
};

struct dpni_cmd_set_unicast_promisc {
	u8 enable;
};

struct dpni_cmd_set_tx_confirmation_mode {
	u32 pad;
	u8 confirmation_mode;
};

struct dpni_cmd_get_queue {
	u8 qtype;
	u8 tc;
	u8 index;
};

#define DPNI_DEST_TYPE_SHIFT	0
#define DPNI_DEST_TYPE_SIZE	4
#define DPNI_STASH_CTRL_SHIFT	6
#define DPNI_STASH_CTRL_SIZE	1
#define DPNI_HOLD_ACTIVE_SHIFT	7
#define DPNI_HOLD_ACTIVE_SIZE	1

struct dpni_rsp_get_queue {
	/* response word 0 */
	__le64 pad0;
	/* response word 1 */
	__le32 dest_id;
	__le16 pad1;
	u8 dest_prio;
	/* From LSB: dest_type:4, pad:2, flc_stash_ctrl:1, hold_active:1 */
	u8 flags;
	/* response word 2 */
	__le64 flc;
	/* response word 3 */
	__le64 user_context;
	/* response word 4 */
	__le32 fqid;
	__le16 qdbin;
};

struct dpni_cmd_set_queue {
	/* cmd word 0 */
	u8 qtype;
	u8 tc;
	u8 index;
	u8 options;
	__le32 pad0;
	/* cmd word 1 */
	__le32 dest_id;
	__le16 pad1;
	u8 dest_prio;
	u8 flags;
	/* cmd word 2 */
	__le64 flc;
	/* cmd word 3 */
	__le64 user_context;
};

#define DPNI_PORT_LOOPBACK_EN_SHIFT	0
#define DPNI_PORT_LOOPBACK_EN_SIZE	1

struct dpni_cmd_set_port_cfg {
	__le32 flags;
	__le32 bit_params;
};

struct dpni_rsp_get_port_cfg {
	__le32 flags;
	__le32 bit_params;
};

int dpni_open(struct fsl_mc_io *mc_io,
	      u32 cmd_flags,
	      int dpni_id,
	      u16 *token)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_open *dpni_cmd;
	int err;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_OPEN,
					  cmd_flags,
					  0);
	dpni_cmd = (struct dpni_cmd_open *)cmd.params;
	dpni_cmd->dpni_id = cpu_to_le32(dpni_id);

	/* send command to mc */
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return err;

	/* retrieve response parameters */
	*token = mc_cmd_hdr_read_token(&cmd);

	return 0;
}

int dpni_close(struct fsl_mc_io *mc_io,
	       u32 cmd_flags,
	       u16 token)
{
	struct fsl_mc_command cmd = { 0 };

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLOSE,
					  cmd_flags,
					  token);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_set_pools(struct fsl_mc_io *mc_io,
		   u32 cmd_flags,
		   u16 token,
		   const struct dpni_pools_cfg *cfg)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_set_pools *dpni_cmd;
	int i;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_POOLS,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_set_pools *)cmd.params;
	dpni_cmd->num_dpbp = cfg->num_dpbp;
	for (i = 0; i < DPNI_MAX_DPBP; i++) {
		dpni_cmd->dpbp_id[i] = cpu_to_le32(cfg->pools[i].dpbp_id);
		dpni_cmd->buffer_size[i] =
			cpu_to_le16(cfg->pools[i].buffer_size);
		dpni_cmd->backup_pool_mask |=
			DPNI_BACKUP_POOL(cfg->pools[i].backup_pool, i);
	}

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_enable(struct fsl_mc_io *mc_io,
		u32 cmd_flags,
		u16 token)
{
	struct fsl_mc_command cmd = { 0 };

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_ENABLE,
					  cmd_flags,
					  token);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_disable(struct fsl_mc_io *mc_io,
		 u32 cmd_flags,
		 u16 token)
{
	struct fsl_mc_command cmd = { 0 };

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_DISABLE,
					  cmd_flags,
					  token);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_is_enabled(struct fsl_mc_io *mc_io,
		    u32 cmd_flags,
		    u16 token,
		    int *en)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_rsp_is_enabled *dpni_rsp;
	int err;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_IS_ENABLED,
					  cmd_flags,
					  token);

	/* send command to mc */
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return err;

	/* retrieve response parameters */
	dpni_rsp = (struct dpni_rsp_is_enabled *)cmd.params;
	*en = dpni_get_field(dpni_rsp->enabled, ENABLE);

	return 0;
}

int dpni_reset(struct fsl_mc_io *mc_io,
	       u32 cmd_flags,
	       u16 token)
{
	struct fsl_mc_command cmd = { 0 };

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET,
					  cmd_flags,
					  token);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_get_attributes(struct fsl_mc_io *mc_io,
			u32 cmd_flags,
			u16 token,
			struct dpni_attr *attr)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_rsp_get_attr *dpni_rsp;

	int err;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_ATTR,
					  cmd_flags,
					  token);

	/* send command to mc */
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return err;

	/* retrieve response parameters */
	dpni_rsp = (struct dpni_rsp_get_attr *)cmd.params;
	attr->options = le32_to_cpu(dpni_rsp->options);
	attr->num_queues = dpni_rsp->num_queues;
	attr->num_tcs = dpni_rsp->num_tcs;
	attr->mac_filter_entries = dpni_rsp->mac_filter_entries;
	attr->vlan_filter_entries = dpni_rsp->vlan_filter_entries;
	attr->qos_entries = dpni_rsp->qos_entries;
	attr->fs_entries = le16_to_cpu(dpni_rsp->fs_entries);
	attr->qos_key_size = dpni_rsp->qos_key_size;
	attr->fs_key_size = dpni_rsp->fs_key_size;
	attr->wriop_version = le16_to_cpu(dpni_rsp->wriop_version);

	return 0;
}

int dpni_set_errors_behavior(struct fsl_mc_io *mc_io,
			     u32 cmd_flags,
			     u16 token,
			     struct dpni_error_cfg *cfg)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_set_errors_behavior *dpni_cmd;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_ERRORS_BEHAVIOR,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_set_errors_behavior *)cmd.params;
	dpni_cmd->errors = cpu_to_le32(cfg->errors);
	dpni_set_field(dpni_cmd->flags, ERROR_ACTION, cfg->error_action);
	dpni_set_field(dpni_cmd->flags, FRAME_ANN, cfg->set_frame_annotation);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_set_buffer_layout(struct fsl_mc_io *mc_io,
			   u32 cmd_flags,
			   u16 token,
			   enum dpni_queue_type qtype,
			   const struct dpni_buffer_layout *layout)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_set_buffer_layout *dpni_cmd;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_BUFFER_LAYOUT,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_set_buffer_layout *)cmd.params;
	dpni_cmd->qtype = qtype;
	dpni_cmd->options = cpu_to_le16(layout->options);
	dpni_set_field(dpni_cmd->flags, PASS_TS, layout->pass_timestamp);
	dpni_set_field(dpni_cmd->flags, PASS_PR, layout->pass_parser_result);
	dpni_set_field(dpni_cmd->flags, PASS_FS, layout->pass_frame_status);
	dpni_cmd->private_data_size = cpu_to_le16(layout->private_data_size);
	dpni_cmd->data_align = cpu_to_le16(layout->data_align);
	dpni_cmd->head_room = cpu_to_le16(layout->data_head_room);
	dpni_cmd->tail_room = cpu_to_le16(layout->data_tail_room);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_get_statistics(struct fsl_mc_io *mc_io,
			u32 cmd_flags,
			u16 token,
			u8 page,
			union dpni_statistics *stat)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_get_statistics *dpni_cmd;
	struct dpni_rsp_get_statistics *dpni_rsp;
	int i, err;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_STATISTICS,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_get_statistics *)cmd.params;
	dpni_cmd->page_number = page;

	/* send command to mc */
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return err;

	/* retrieve response parameters */
	dpni_rsp = (struct dpni_rsp_get_statistics *)cmd.params;
	for (i = 0; i < DPNI_STATISTICS_CNT; i++)
		stat->raw.counter[i] = le64_to_cpu(dpni_rsp->counter[i]);

	return 0;
}

int dpni_reset_statistics(struct fsl_mc_io *mc_io,
			  u32 cmd_flags,
			  u16 token)
{
	struct fsl_mc_command cmd = { 0 };

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET_STATISTICS,
					  cmd_flags,
					  token);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_get_link_cfg(struct fsl_mc_io *mc_io,
		      u32 cmd_flags,
		      u16 token,
		      struct dpni_link_cfg *cfg)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_link_cfg *dpni_rsp;
	int err;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_LINK_CFG,
					  cmd_flags,
					  token);

	/* send command to mc */
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return err;

	/* retrieve response parameters */
	dpni_rsp = (struct dpni_cmd_link_cfg *)cmd.params;
	cfg->rate = le32_to_cpu(dpni_rsp->rate);
	cfg->options = le64_to_cpu(dpni_rsp->options);
	cfg->advertising = le64_to_cpu(dpni_rsp->advertising);

	return 0;
}

int dpni_set_link_cfg(struct fsl_mc_io *mc_io,
		      u32 cmd_flags,
		      u16 token,
		      const struct dpni_link_cfg *cfg)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_link_cfg *dpni_cmd;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_LINK_CFG,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_link_cfg *)cmd.params;
	dpni_cmd->rate = cpu_to_le32(cfg->rate);
	dpni_cmd->options = cpu_to_le64(cfg->options);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_set_link_cfg_v2(struct fsl_mc_io *mc_io,
			 u32 cmd_flags,
			 u16 token,
			 const struct dpni_link_cfg *cfg)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_set_link_cfg *dpni_cmd;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_LINK_CFG_V2,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_set_link_cfg *)cmd.params;
	dpni_cmd->rate = cpu_to_le32(cfg->rate);
	dpni_cmd->options = cpu_to_le64(cfg->options);
	dpni_cmd->advertising = cpu_to_le64(cfg->advertising);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_get_link_state(struct fsl_mc_io *mc_io,
			u32 cmd_flags,
			u16 token,
			struct dpni_link_state *state)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_rsp_get_link_state *dpni_rsp;
	int err;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_LINK_STATE,
					  cmd_flags,
					  token);

	/* send command to mc */
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return err;

	/* retrieve response parameters */
	dpni_rsp = (struct dpni_rsp_get_link_state *)cmd.params;
	state->up = dpni_get_field(dpni_rsp->flags, LINK_STATE);
	state->rate = le32_to_cpu(dpni_rsp->rate);
	state->options = le64_to_cpu(dpni_rsp->options);

	return 0;
}

int dpni_get_link_state_v2(struct fsl_mc_io *mc_io,
			   u32 cmd_flags,
			   u16 token,
			   struct dpni_link_state *state)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_rsp_get_link_state *dpni_rsp;
	int err;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_LINK_STATE_V2,
					  cmd_flags,
					  token);

	/* send command to mc */
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return err;

	/* retrieve response parameters */
	dpni_rsp = (struct dpni_rsp_get_link_state *)cmd.params;
	state->up = dpni_get_field(dpni_rsp->flags, LINK_STATE);
	state->state_valid = dpni_get_field(dpni_rsp->flags, STATE_VALID);
	state->rate = le32_to_cpu(dpni_rsp->rate);
	state->options = le64_to_cpu(dpni_rsp->options);
	state->supported = le64_to_cpu(dpni_rsp->supported);
	state->advertising = le64_to_cpu(dpni_rsp->advertising);

	return 0;
}

int dpni_set_max_frame_length(struct fsl_mc_io *mc_io,
			      u32 cmd_flags,
			      u16 token,
			      u16 max_frame_length)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_set_max_frame_length *dpni_cmd;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_MAX_FRAME_LENGTH,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_set_max_frame_length *)cmd.params;
	dpni_cmd->max_frame_length = cpu_to_le16(max_frame_length);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_set_multicast_promisc(struct fsl_mc_io *mc_io,
			       u32 cmd_flags,
			       u16 token,
			       int en)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_set_multicast_promisc *dpni_cmd;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_MCAST_PROMISC,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_set_multicast_promisc *)cmd.params;
	dpni_set_field(dpni_cmd->enable, ENABLE, en);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_set_unicast_promisc(struct fsl_mc_io *mc_io,
			     u32 cmd_flags,
			     u16 token,
			     int en)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_set_unicast_promisc *dpni_cmd;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_UNICAST_PROMISC,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_set_unicast_promisc *)cmd.params;
	dpni_set_field(dpni_cmd->enable, ENABLE, en);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_set_tx_confirmation_mode(struct fsl_mc_io *mc_io,
				  u32 cmd_flags,
				  u16 token,
				  enum dpni_confirmation_mode mode)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_set_tx_confirmation_mode *dpni_cmd;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_CONFIRMATION_MODE,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_set_tx_confirmation_mode *)cmd.params;
	dpni_cmd->confirmation_mode = mode;

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_set_queue(struct fsl_mc_io *mc_io,
		   u32 cmd_flags,
		   u16 token,
		   enum dpni_queue_type qtype,
		   u8 tc,
		   u8 index,
		   u8 options,
		   const struct dpni_queue *queue)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_set_queue *dpni_cmd;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_QUEUE,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_set_queue *)cmd.params;
	dpni_cmd->qtype = qtype;
	dpni_cmd->tc = tc;
	dpni_cmd->index = index;
	dpni_cmd->options = options;
	dpni_cmd->dest_id = cpu_to_le32(queue->destination.id);
	dpni_cmd->dest_prio = queue->destination.priority;
	dpni_set_field(dpni_cmd->flags, DEST_TYPE, queue->destination.type);
	dpni_set_field(dpni_cmd->flags, STASH_CTRL, queue->flc.stash_control);
	dpni_set_field(dpni_cmd->flags, HOLD_ACTIVE,
		       queue->destination.hold_active);
	dpni_cmd->flc = cpu_to_le64(queue->flc.value);
	dpni_cmd->user_context = cpu_to_le64(queue->user_context);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_get_queue(struct fsl_mc_io *mc_io,
		   u32 cmd_flags,
		   u16 token,
		   enum dpni_queue_type qtype,
		   u8 tc,
		   u8 index,
		   struct dpni_queue *queue,
		   struct dpni_queue_id *qid)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_get_queue *dpni_cmd;
	struct dpni_rsp_get_queue *dpni_rsp;
	int err;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_QUEUE,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_get_queue *)cmd.params;
	dpni_cmd->qtype = qtype;
	dpni_cmd->tc = tc;
	dpni_cmd->index = index;

	/* send command to mc */
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return err;

	/* retrieve response parameters */
	dpni_rsp = (struct dpni_rsp_get_queue *)cmd.params;
	queue->destination.id = le32_to_cpu(dpni_rsp->dest_id);
	queue->destination.priority = dpni_rsp->dest_prio;
	queue->destination.type = dpni_get_field(dpni_rsp->flags,
						     DEST_TYPE);
	queue->flc.stash_control = dpni_get_field(dpni_rsp->flags,
						  STASH_CTRL);
	queue->destination.hold_active = dpni_get_field(dpni_rsp->flags,
							HOLD_ACTIVE);
	queue->flc.value = le64_to_cpu(dpni_rsp->flc);
	queue->user_context = le64_to_cpu(dpni_rsp->user_context);
	qid->fqid = le32_to_cpu(dpni_rsp->fqid);
	qid->qdbin = le16_to_cpu(dpni_rsp->qdbin);

	return 0;
}

int dpni_set_port_cfg(struct fsl_mc_io *mc_io,
		      u32 cmd_flags,
		      u16 token,
		      u32 flags,
		      struct dpni_port_cfg *port_cfg)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_cmd_set_port_cfg *dpni_cmd;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_PORT_CFG,
					  cmd_flags,
					  token);
	dpni_cmd = (struct dpni_cmd_set_port_cfg *)cmd.params;
	dpni_cmd->flags = cpu_to_le32(flags);
	dpni_set_field(dpni_cmd->bit_params, PORT_LOOPBACK_EN, !!port_cfg->loopback_en);

	/* send command to mc */
	return mc_send_command(mc_io, &cmd);
}

int dpni_get_port_cfg(struct fsl_mc_io *mc_io,
		      u32 cmd_flags,
		      u16 token,
		      u32 flags,
		      struct dpni_port_cfg *port_cfg)
{
	struct fsl_mc_command cmd = { 0 };
	struct dpni_rsp_get_port_cfg *dpni_rsp;
	int err;

	/* prepare command */
	cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_PORT_CFG,
					  cmd_flags,
					  token);

	/* send command to mc */
	err = mc_send_command(mc_io, &cmd);
	if (err)
		return err;

	dpni_rsp = (struct dpni_rsp_get_port_cfg *)cmd.params;
	port_cfg->loopback_en = dpni_get_field(dpni_rsp->bit_params, PORT_LOOPBACK_EN);

	return 0;
}
